import base64
from enum import StrEnum
from typing import Optional, Any, Dict, TypeAlias

from pydantic import BaseModel

RawExtension: TypeAlias = Dict[str, Any]


class Operation(StrEnum):
    CREATE = "CREATE"
    UPDATE = "UPDATE"
    DELETE = "DELETE"
    CONNECT = "CONNECT"


class Kind(StrEnum):
    DEPLOYMENT = "Deployment"
    STATEFUL_SET = "StatefulSet"
    DAEMON_SET = "DaemonSet"


class GroupVersionKind(BaseModel):
    group: Optional[str] = None
    version: Optional[str] = None
    kind: Optional[Kind] = None


class GroupVersionResource(BaseModel):
    group: Optional[str] = None
    version: Optional[str] = None
    resource: Optional[str] = None


class AdmissionRequest(BaseModel):
    uid: str
    kind: GroupVersionKind
    resource: Optional[GroupVersionResource] = None
    subResource: Optional[str] = None
    requestKind: Optional[GroupVersionKind] = None
    requestResource: Optional[GroupVersionResource] = None
    requestSubResource: Optional[str] = None
    name: Optional[str] = None
    namespace: Optional[str] = None
    operation: Optional[Operation] = None
    userInfo: Dict[str, Any]
    object: Optional[RawExtension] = None
    oldObject: Optional[RawExtension] = None
    dryRun: Optional[bool] = None
    options: Optional[RawExtension] = None


class Status(BaseModel):
    status: Optional[str] = None
    message: Optional[str] = None
    reason: Optional[str] = None
    code: Optional[int] = None


class Op(StrEnum):
    add = "add"
    remove = "remove"
    replace_ = "replace"


class PatchOperation(BaseModel):
    op: Op
    path: str
    value: Optional[Dict | str] = None


class AdmissionResponse(BaseModel):
    uid: str
    allowed: bool
    status: Optional[Status] = None
    patch: Optional[bytes] = None
    patchType: Optional[str] = None

    model_config = {
        "json_encoders": {
            bytes: lambda v: base64.b64encode(v).decode()
        }
    }


class TypeMeta(BaseModel):
    apiVersion: str
    kind: str


class AdmissionReviewRequest(TypeMeta):
    request: AdmissionRequest


class AdmissionReviewResponse(TypeMeta):
    response: AdmissionResponse
